今天我們來做個housekeeping,整理一下程式。
首先將邊界條件及初始速度,獨立出各自的creator function
,放於creators.py
中,過程與其它creator function
類似,不再贅述。
#creators.py
def create_boundary_spc(fields, deck=None):
deck = deck or constants.LSDYNA
type_ = BCType.BOUNDARY_SPC_SET
return base.CreateEntity(deck, type_, fields)
def create_initial_velocity(fields, deck=None):
deck = deck or constants.LSDYNA
type_ = BCType.INITIAL_VELOCITY_SET
return base.CreateEntity(deck, type_, fields)
接著建立一個card_handlers.py
來處理control
及database
的control card
。
由於ANSA內允許創造多個control card
或是database
的Entity
,有時會造成一些輸出的困擾,所以我們會希望盡量減少這類Entity的數量。透過_get_card_ent
,我們可以回傳第一個由base.CollectEntities
所收集到的Entity
。如果ANSA環境內沒有該Entity
,我們則建立並回傳。
#card_handlers.py
def get_card_ent(type_, deck=None):
deck = deck or constants.LSDYNA
ents = base.CollectEntities(deck, None, type_)
if ents:
return ents[0]
return base.CreateEntity(deck, type_)
card_handler
需要ent
、params
及deck
三個參數。ctrl_params
的格式為一list
,裡面每個元素為一個含有兩個元素的tuple
。tuple
的第一個元素為*CONTROL
或*DATABASE
等keyword
後的後綴(不含底線),第二個元素為一dict
,內含想設定的參數及其值。這樣的話,我們就可以透過下面的語法來設定control
或database
等control card
。
#*CONTROL_TERMINATION
crtl_ent = get_card_ent(ControlCardType.CONTROL)
ctrl_params = [('TERMINATION', {'ENDTIM': 1.5E-2})]
crtl_ent = card_handler(crtl_ent, ctrl_params)
如Day07提到的,這類型Entity
最tricky的地方就是必須要先ON
,剩下的就是將params
內給定的參數提取出來,放入fields
內,最後透過set_entity_values
一次設定完成。
#card_handlers.py
def card_handler(ent, params, deck=None):
deck = deck or constants.LSDYNA
fields = {}
for keyword, fields_ in params:
fields[keyword] = 'ON'
ent.set_entity_values(deck, fields=fields)
if fields_:
fields.update({(keyword + '_' + k): v
for k, v in fields_.items()})
ent.set_entity_values(deck, fields=fields)
return ent
建立一個utils.py
來儲存一些utility function
。
set_deck_to
為一helper function
,可透過此function
將當前ANSA deck
設為LS-DYNA。
#utils.py
def set_deck_to(deck=None):
deck = deck or constants.LSDYNA
base.SetCurrentDeck(deck)
set_zoom_all_view
呼叫base.ZoomAll
,僅是方便視角的呈現。
#utils.py
def set_zoom_all_view():
base.ZoomAll()
set_obj_visible_for_output_deck
將需要設定為輸出的contact
,邊界條件及初始速度等,打包放入一個函數,方便使用。
#utils.py
def set_obj_visible_for_output_deck(deck=None):
deck = deck or constants.LSDYNA
keys = {LSDYNAType.CONTACT,
BCType.BOUNDARY_SPC_SET,
BCType.INITIAL_VELOCITY_SET}
base.SetEntityVisibilityValues(deck, {key.value: 'on' for key in keys})
將輸出相關設定移至output_file function
。
#utils.py
def output_file(filename, deck=None):
deck = deck or constants.LSDYNA
base_dir = Path(__file__).parent
file_str = (base_dir / filename).as_posix()
set_obj_visible_for_output_deck(deck)
base.OutputLSDyna(filename=file_str)
base.SetEntityVisibilityValues(deck, {"CONTACT": "off"})
set_zoom_all_view()
return file_str
將求解相關設定移至run_dyna function
。除了檔名路徑是必要輸入參數外,solver的路徑、想使用的cpu
數量、想使用的memory
大小及額外控制,都透過short circuit技巧給定了預設值。
#utils.py
def run_dyna(file_str,
solver_str=None,
ncpu=None,
memory=None,
d=None):
solver_str = solver_str or f'{Path.home()}/LS-DYNA/13.0/smp-dyna_s'
i = f'i={file_str}'
ncpu = f'ncpu={ncpu}' if ncpu is not None else f'ncpu=8'
memory = f'memory={memory}' if memory is not None else f'memory=1000m'
d = f'd={d}' if d is not None else f'd=nodump'
commands = [solver_str, i, ncpu, memory, d]
subprocess.run(commands)